home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
nethack.lha
/
nethack-3.1
/
src
/
makemon.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-22
|
41KB
|
1,532 lines
/* SCCS Id: @(#)makemon.c 3.1 92/11/01 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "epri.h"
#include "emin.h"
#ifdef REINCARNATION
# include <ctype.h>
#endif
STATIC_VAR struct monst NEARDATA zeromonst;
#define uncommon(ptr) \
(((ptr)->geno & (G_GENOD | G_EXTINCT | G_NOGEN | G_UNIQ)) || \
(!Inhell ? ((ptr)->geno & G_HELL) : ((ptr)->maligntyp > A_NEUTRAL)))
#ifdef OVL0
static boolean NDECL(cmavail);
static int FDECL(align_shift, (struct permonst *));
#endif /* OVL0 */
STATIC_DCL boolean FDECL(is_home_elemental,(struct permonst *));
STATIC_DCL boolean FDECL(wrong_elem_type, (struct permonst *));
STATIC_DCL void FDECL(m_initgrp,(struct monst *,int,int,int));
STATIC_DCL void FDECL(m_initthrow,(struct monst *,int,int));
STATIC_DCL void FDECL(m_initweap,(struct monst *));
#ifdef OVL1
static void FDECL(m_initinv,(struct monst *));
#endif /* OVL1 */
extern int monstr[];
#define m_initsgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 3)
#define m_initlgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 10)
#define toostrong(monindx, lev) (monstr[monindx] > lev)
#define tooweak(monindx, lev) (monstr[monindx] < lev)
#ifdef OVLB
STATIC_OVL boolean
is_home_elemental(ptr)
register struct permonst *ptr;
{
if (ptr->mlet != S_ELEMENTAL) return FALSE;
if (!In_endgame(&u.uz)) return FALSE;
switch(monsndx(ptr)) {
case PM_AIR_ELEMENTAL: return Is_airlevel(&u.uz);
case PM_FIRE_ELEMENTAL: return Is_firelevel(&u.uz);
case PM_EARTH_ELEMENTAL: return Is_earthlevel(&u.uz);
case PM_WATER_ELEMENTAL: return Is_waterlevel(&u.uz);
}
return FALSE; /* shouldn't be reached */
}
/*
* Return true if the given monster cannot exist on this elemental level.
*/
STATIC_OVL boolean
wrong_elem_type(ptr)
register struct permonst *ptr;
{
if (Is_earthlevel(&u.uz)) {
/* no restrictions? */
} else if (Is_waterlevel(&u.uz)) {
/* just monsters that can swim */
if(!is_swimmer(ptr)) return TRUE;
} else if (Is_firelevel(&u.uz)) {
if(!resists_fire(ptr)) return TRUE;
} else if (Is_airlevel(&u.uz)) {
if(!(is_flyer(ptr) && ptr->mlet != S_TRAPPER) && !is_floater(ptr)
&& !amorphous(ptr) && !noncorporeal(ptr) && !is_whirly(ptr))
return TRUE;
}
return FALSE;
}
STATIC_OVL void
m_initgrp(mtmp, x, y, n) /* make a group just like mtmp */
register struct monst *mtmp;
register int x, y, n;
{
coord mm;
register int cnt = rnd(n);
struct monst *mon;
/*
* Temporary kludge to cut down on swarming at lower character levels
* till we can get this game a little more balanced. [mrs]
*/
cnt /= (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1;
if(!cnt) cnt++;
mm.x = x;
mm.y = y;
while(cnt--) {
if (peace_minded(mtmp->data)) continue;
/* Don't create groups of peaceful monsters since they'll get
* in our way. If the monster has a percentage chance so some
* are peaceful and some are not, the result will just be a
* smaller group.
*/
if (enexto(&mm, mm.x, mm.y, mtmp->data)) {
mon = makemon(mtmp->data, mm.x, mm.y);
mon->mpeaceful = FALSE;
set_malign(mon);
/* Undo the second peace_minded() check in makemon(); if the
* monster turned out to be peaceful the first time we
* didn't create it at all; we don't want a second check.
*/
}
}
}
STATIC_OVL
void
m_initthrow(mtmp,otyp,oquan)
struct monst *mtmp;
int otyp,oquan;
{
register struct obj *otmp;
otmp = mksobj(otyp, TRUE, FALSE);
otmp->quan = (long) rn1(oquan, 3);
otmp->owt = weight(otmp);
if (otyp == ORCISH_ARROW) otmp->opoisoned = TRUE;
mpickobj(mtmp, otmp);
}
#endif /* OVLB */
#ifdef OVL2
STATIC_OVL void
m_initweap(mtmp)
register struct monst *mtmp;
{
register struct permonst *ptr = mtmp->data;
register int mm = monsndx(ptr);
#ifdef REINCARNATION
if (Is_rogue_level(&u.uz)) return;
#endif
/*
* first a few special cases:
*
* giants get a boulder to throw sometimes.
* ettins get clubs
* kobolds get darts to throw
* centaurs get some sort of bow & arrows or bolts
* soldiers get all sorts of things.
* kops get clubs & cream pies.
*/
switch (mtmp->data->mlet) {
case S_GIANT:
if (rn2(2)) (void)mongets(mtmp, (ptr != &mons[PM_ETTIN]) ?
BOULDER : CLUB);
break;
case S_HUMAN:
if(is_mercenary(ptr)) {
int w1 = 0, w2 = 0;
switch (mm) {
case PM_WATCHMAN:
#ifdef ARMY
case PM_SOLDIER:
#endif
if (!rn2(3)) {
w1 = rn1(BEC_DE_CORBIN - PARTISAN + 1, PARTISAN);
w2 = rn2(2) ? DAGGER : KNIFE;
} else w1 = rn2(2) ? SPEAR : SHORT_SWORD;
break;
#ifdef ARMY
case PM_SERGEANT:
w1 = rn2(2) ? FLAIL : MACE;
break;
case PM_LIEUTENANT:
w1 = rn2(2) ? BROADSWORD : LONG_SWORD;
break;
case PM_CAPTAIN:
#endif
case PM_WATCH_CAPTAIN:
w1 = rn2(2) ? LONG_SWORD : SILVER_SABER;
break;
default:
if (!rn2(4)) w1 = DAGGER;
if (!rn2(7)) w2 = SPEAR;
break;
}
if (w1) (void)mongets(mtmp, w1);
if (!w2 && w1 != DAGGER && !rn2(4)) w2 = KNIFE;
if (w2) (void)mongets(mtmp, w2);
} else if (is_elf(ptr)) {
if (rn2(2))
(void) mongets(mtmp,
rn2(2) ? ELVEN_MITHRIL_COAT : ELVEN_CLOAK);
if (rn2(2)) (void)mongets(mtmp, ELVEN_LEATHER_HELM);
else if (!rn2(4)) (void)mongets(mtmp, ELVEN_BOOTS);
if (rn2(2)) (void)mongets(mtmp, ELVEN_DAGGER);
switch (rn2(3)) {
case 0:
if (!rn2(4)) (void)mongets(mtmp, ELVEN_SHIELD);
if (rn2(3)) (void)mongets(mtmp, ELVEN_SHORT_SWORD);
(void)mongets(mtmp, ELVEN_BOW);
m_initthrow(mtmp, ELVEN_ARROW, 12);
break;
case 1:
(void)mongets(mtmp, ELVEN_BROADSWORD);
if (rn2(2)) (void)mongets(mtmp, ELVEN_SHIELD);
break;
case 2:
if (rn2(2)) {
(void)mongets(mtmp, ELVEN_SPEAR);
(void)mongets(mtmp, ELVEN_SHIELD);
}
break;
}
if(mtmp->data == &mons[PM_ELVENKING])
(void)mongets(mtmp, PICK_AXE);
}
break;
case S_ANGEL:
{
int spe2;
/* create minion stuff; can't use mongets */
struct obj *otmp = mksobj(LONG_SWORD, FALSE, FALSE);
/* maybe make it special */
if(!rn2(20) || is_lord(mtmp->data))
otmp = oname(otmp, artiname(
rn2(2) ? ART_DEMONBANE : ART_SUNSWORD), 0);
bless(otmp);
otmp->oerodeproof = TRUE;
spe2 = rn2(4);
otmp->spe = max(otmp->spe, spe2);
mpickobj(mtmp, otmp);
otmp = mksobj(!rn2(4) || is_lord(mtmp->data) ?
SHIELD_OF_REFLECTION : LARGE_SHIELD,
FALSE, FALSE);
otmp->cursed = FALSE;
otmp->oerodeproof = TRUE;
otmp->spe = 0;
mpickobj(mtmp, otmp);
}
break;
case S_HUMANOID:
if (mm == PM_HOBBIT) {
switch (rn2(3)) {
case 0:
(void)mongets(mtmp, DAGGER);
break;
case 1:
(void)mongets(mtmp, ELVEN_DAGGER);
break;
case 2:
(void)mongets(mtmp, SLING);
break;
}
if (!rn2(10)) (void)mongets(mtmp, ELVEN_MITHRIL_COAT);
if (!rn2(10)) (void)mongets(mtmp, DWARVISH_CLOAK);
} else if (is_dwarf(ptr)) {
if (rn2(7)) (void)mongets(mtmp, DWARVISH_CLOAK);
if (rn2(7)) (void)mongets(mtmp, IRON_SHOES);
if (!rn2(4)) {
(void)mongets(mtmp, DWARVISH_SHORT_SWORD);
/* note: you can't use a mattock with a shield */
if (rn2(2)) (void)mongets(mtmp, DWARVISH_MATTOCK);
else {
(void)mongets(mtmp, AXE);
(void)mongets(mtmp, DWARVISH_ROUNDSHIELD);
}
(void)mongets(mtmp, DWARVISH_IRON_HELM);
if (!rn2(3))
(void)mongets(mtmp, DWARVISH_MITHRIL_COAT);
} else {
(void)mongets(mtmp, !rn2(3) ? PICK_AXE : DAGGER);
}
}
break;
# ifdef KOPS
case S_KOP: /* create Keystone Kops with cream pies to
* throw. As suggested by KAA. [MRS]
*/
if (!rn2(4)) m_initthrow(mtmp, CREAM_PIE, 2);
if (!rn2(3)) (void)mongets(mtmp,(rn2(2)) ? CLUB : RUBBER_HOSE);
break;
# endif
case S_ORC:
if(rn2(2)) (void)mongets(mtmp, ORCISH_HELM);
switch (mm != PM_ORC_CAPTAIN ? mm :
rn2(2) ? PM_MORDOR_ORC : PM_URUK_HAI) {
case PM_MORDOR_ORC:
if(!rn2(3)) (void)mongets(mtmp, SCIMITAR);
if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHIELD);
if(!rn2(3)) (void)mongets(mtmp, KNIFE);
if(!rn2(3)) (void)mongets(mtmp, ORCISH_CHAIN_MAIL);
break;
case PM_URUK_HAI:
if(!rn2(3)) (void)mongets(mtmp, ORCISH_CLOAK);
if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHORT_SWORD);
if(!rn2(3)) (void)mongets(mtmp, IRON_SHOES);
if(!rn2(3)) {
(void)mongets(mtmp, ORCISH_BOW);
m_initthrow(mtmp, ORCISH_ARROW, 12);
}
if(!rn2(3)) (void)mongets(mtmp, URUK_HAI_SHIELD);
break;
default:
if (mm != PM_ORC_SHAMAN && rn2(2))
(void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0)
? ORCISH_DAGGER : SCIMITAR);
}
break;
case S_OGRE:
if (!rn2(mm == PM_OGRE_KING ? 3 : mm == PM_OGRE_LORD ? 6 : 12))
(void) mongets(mtmp, BATTLE_AXE);
break;
case S_KOBOLD:
if (!rn2(4)) m_initthrow(mtmp, DART, 12);
break;
case S_CENTAUR:
if (rn2(2)) {
if(ptr == &mons[PM_FOREST_CENTAUR]) {
(void)mongets(mtmp, BOW);
m_initthrow(mtmp, ARROW, 12);
} else {
(void)mongets(mtmp, CROSSBOW);
m_initthrow(mtmp, CROSSBOW_BOLT, 12);
}
}
break;
case S_WRAITH:
(void)mongets(mtmp, KNIFE);
(void)mongets(mtmp, LONG_SWORD);
break;
case S_DEMON:
switch (mm) {
case PM_BALROG:
(void)mongets(mtmp, BULLWHIP);
(void)mongets(mtmp, BROADSWORD);
break;
case PM_ORCUS:
(void)mongets(mtmp, WAN_DEATH); /* the Wand of Orcus */
break;
case PM_HORNED_DEVIL:
(void)mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP);
break;
case PM_ICE_DEVIL:
if (!rn2(4)) (void)mongets(mtmp, SPEAR);
break;
case PM_ASMODEUS:
(void)mongets(mtmp, WAN_COLD);
break;
case PM_DISPATER:
(void)mongets(mtmp, WAN_STRIKING);
break;
case PM_YEENOGHU:
(void)mongets(mtmp, FLAIL);
break;
}
/* prevent djinnis and mail daemons from leaving objects when
* they vanish
*/
if (!is_demon(ptr)) break;
/* fall thru */
/*
* Now the general case, ~40% chance of getting some type
* of weapon. TODO: Add more weapons types (use bigmonst());
*/
default:
switch(rnd(12)) {
case 1:
m_initthrow(mtmp, DART, 12);
break;
case 2:
(void) mongets(mtmp, CROSSBOW);
m_initthrow(mtmp, CROSSBOW_BOLT, 12);
break;
case 3:
(void) mongets(mtmp, BOW);
m_initthrow(mtmp, ARROW, 12);
break;
case 4:
m_initthrow(mtmp, DAGGER, 3);
break;
case 5:
(void) mongets(mtmp, AKLYS);
break;
default:
break;
}
break;
}
#ifdef MUSE
if ((int) mtmp->m_lev > rn2(70))
(void) mongets(mtmp, rnd_offensive_item(mtmp));
#endif
}
#endif /* OVL2 */
#ifdef OVL1
static void
m_initinv(mtmp)
register struct monst *mtmp;
{
register int cnt;
register struct obj *otmp;
register struct permonst *ptr = mtmp->data;
#ifdef REINCARNATION
if (Is_rogue_level(&u.uz)) return;
#endif
/*
* Soldiers get armour & rations - armour approximates their ac.
* Nymphs may get mirror or potion of object detection.
*/
switch(ptr->mlet) {
case S_HUMAN:
if(is_mercenary(ptr)) {
register int mac;
#ifdef MUSE
switch(monsndx(ptr)) {
case PM_GUARD: mac = -1; break;
# ifdef ARMY
case PM_SOLDIER: mac = 3; break;
case PM_SERGEANT: mac = 0; break;
case PM_LIEUTENANT: mac = -2; break;
case PM_CAPTAIN: mac = -3; break;
# endif
case PM_WATCHMAN: mac = 3; break;
case PM_WATCH_CAPTAIN: mac = -2; break;
default: impossible("odd mercenary %d?", monsndx(ptr));
mac = 0;
break;
}
#else
mac = ptr->ac;
#endif
if (mac < -1 && rn2(5))
mac += 7 + mongets(mtmp, (rn2(5)) ?
PLATE_MAIL : CRYSTAL_PLATE_MAIL);
else if (mac < 3 && rn2(5))
mac += 6 + mongets(mtmp, (rn2(3)) ?
SPLINT_MAIL : BANDED_MAIL);
else if (rn2(5))
mac += 3 + mongets(mtmp, (rn2(3)) ?
RING_MAIL : STUDDED_LEATHER_ARMOR);
else
mac += 2 + mongets(mtmp, LEATHER_ARMOR);
if (mac < 10 && rn2(3))
mac += 1 + mongets(mtmp, HELMET);
else if (mac < 10 && rn2(2))
mac += 1 + mongets(mtmp, DENTED_POT);
if (mac < 10 && rn2(3))
mac += 1 + mongets(mtmp, SMALL_SHIELD);
else if (mac < 10 && rn2(2))
mac += 2 + mongets(mtmp, LARGE_SHIELD);
if (mac < 10 && rn2(3))
mac += 1 + mongets(mtmp, LOW_BOOTS);
else if (mac < 10 && rn2(2))
mac += 2 + mongets(mtmp, HIGH_BOOTS);
if (mac < 10 && rn2(3))
mac += 1 + mongets(mtmp, LEATHER_GLOVES);
else if (mac < 10 && rn2(2))
mac += 1 + mongets(mtmp, ELVEN_CLOAK);
#ifndef MUSE
if (mac != 10 && rn2(5)) { /* make up the difference */
otmp = mksobj(RIN_PROTECTION, FALSE, FALSE);
otmp->spe = (10 - mac + rn2(3) - rn2(3));
if(otmp->spe < 0) curse(otmp);
mpickobj(mtmp, otmp);
}
#endif
#ifdef ARMY
if(ptr != &mons[PM_GUARD] &&
ptr != &mons[PM_WATCHMAN] &&
ptr != &mons[PM_WATCH_CAPTAIN]) {
if (!rn2(3)) (void) mongets(mtmp, K_RATION);
if (!rn2(2)) (void) mongets(mtmp, C_RATION);
# ifdef MUSE
if (ptr != &mons[PM_SOLDIER] && !rn2(3))
(void) mongets(mtmp, BUGLE);
# endif
} else
#endif
if (ptr == &mons[PM_WATCHMAN] && rn2(3))
(void) mongets(mtmp, TIN_WHISTLE);
} else if (ptr == &mons[PM_SHOPKEEPER]) {
(void) mongets(mtmp,SKELETON_KEY);
}
break;
case S_NYMPH:
if(!rn2(2)) (void) mongets(mtmp, MIRROR);
if(!rn2(2)) (void) mongets(mtmp, POT_OBJECT_DETECTION);
break;
case S_GIANT:
if (ptr == &mons[PM_MINOTAUR])
(void) mongets(mtmp, WAN_DIGGING);
else if (is_giant(ptr)) {
for(cnt = rn2((int)(mtmp->m_lev / 2)); cnt; cnt--) {
otmp = mksobj(rnd_class(DILITHIUM_CRYSTAL,LUCKSTONE-1),FALSE,FALSE);
otmp->quan = (long) rn1(2, 3);
otmp->owt = weight(otmp);
mpickobj(mtmp, otmp);
}
}
break;
case S_WRAITH:
if (ptr == &mons[PM_NAZGUL]) {
otmp = mksobj(RIN_INVISIBILITY, FALSE, FALSE);
curse(otmp);
mpickobj(mtmp, otmp);
}
break;
case S_QUANTMECH:
if (!rn2(20)) {
struct obj *cat;
otmp = mksobj(LARGE_BOX, FALSE, FALSE);
/* actually, whether this is a corpse or a live cat shouldn't
really be decided until the box is opened... */
cat = mksobj(CORPSE, FALSE, FALSE);
cat->corpsenm = PM_HOUSECAT;
cat->owt = weight(cat);
cat = oname(cat, "Schroedinger's Cat", FALSE);
cat->nobj = otmp->cobj;
otmp->cobj = cat;
otmp->owt = weight(otmp);
mpickobj(mtmp, otmp);
}
break;
case S_LEPRECHAUN:
mtmp->mgold = (long) d(level_difficulty(), 30);
break;
default:
break;
}
#ifdef ARMY /* ordinary soldiers rarely have access to magic (or gold :-) */
if (ptr == &mons[PM_SOLDIER] && rn2(13)) return;
#endif
#ifdef MUSE
if ((int) mtmp->m_lev > rn2(30))
(void) mongets(mtmp, rnd_defensive_item(mtmp));
if ((int) mtmp->m_lev > rn2(100))
(void) mongets(mtmp, rnd_misc_item(mtmp));
#endif
if (likes_gold(ptr) && !mtmp->mgold && !rn2(5))
mtmp->mgold =
(long) d(level_difficulty(), mtmp->minvent ? 5 : 10);
}
/*
* called with [x,y] = coordinates;
* [0,0] means anyplace
* [u.ux,u.uy] means: near player (if !in_mklev)
*
* In case we make a monster group, only return the one at [x,y].
*/
struct monst *
makemon(ptr, x, y)
register struct permonst *ptr;
register int x, y;
{
register struct monst *mtmp;
register int ct;
boolean anything = (!ptr);
boolean byyou = (x == u.ux && y == u.uy);
/* if caller wants random location, do it here */
if(x == 0 && y == 0) {
int tryct = 0; /* careful with bigrooms */
do {
x = rn1(COLNO-3,2);
y = rn2(ROWNO);
} while(!goodpos(x, y, (struct monst *)0, ptr) ||
(!in_mklev && tryct++ < 50 && cansee(x, y)));
} else if (byyou && !in_mklev) {
coord bypos;
if(enexto(&bypos, u.ux, u.uy, ptr)) {
x = bypos.x;
y = bypos.y;
} else
return((struct monst *)0);
}
/* if a monster already exists at the position, return */
if(MON_AT(x, y))
return((struct monst *) 0);
if(ptr){
/* if you are to make a specific monster and it has
already been genocided, return */
if(ptr->geno & G_GENOD) return((struct monst *) 0);
} else {
/* make a random (common) monster that can survive here.
* (the special levels ask for random monsters at specific
* positions, causing mass drowning on the medusa level,
* for instance.)
*/
int tryct = 0; /* maybe there are no good choices */
do {
if(!(ptr = rndmonst())) {
#ifdef DEBUG
pline("Warning: no monster.");
#endif
return((struct monst *) 0); /* no more monsters! */
}
} while(!goodpos(x, y, (struct monst *)0, ptr) && tryct++ < 50);
}
/* if it's unique, don't ever make it again */
if (ptr->geno & G_UNIQ) ptr->geno |= G_EXTINCT;
mtmp = newmonst(ptr->pxlth);
*mtmp = zeromonst; /* clear all entries in structure */
for(ct = 0; ct < ptr->pxlth; ct++)
((char *) &(mtmp->mextra[0]))[ct] = 0;
mtmp->nmon = fmon;
fmon = mtmp;
mtmp->m_id = flags.ident++;
mtmp->data = ptr;
mtmp->mxlth = ptr->pxlth;
mtmp->m_lev = adj_lev(ptr);
if (is_golem(ptr))
mtmp->mhpmax = mtmp->mhp = golemhp(monsndx(ptr));
else if (is_rider(ptr)) {
/* We want low HP, but a high mlevel so they can attack well */
mtmp->mhpmax = mtmp->mhp = d(10,8);
} else if(ptr->mlevel > 49) {
/* "special" fixed hp monster
* the hit points are encoded in the mlevel in a somewhat strange
* way to fit in the 50..127 positive range of a signed character
* above the 1..49 that indicate "normal" monster levels */
mtmp->mhpmax = mtmp->mhp = 2*(ptr->mlevel - 6);
mtmp->m_lev = mtmp->mhp / 4; /* approximation */
} else if((ptr->mlet == S_DRAGON) && (ptr >= &mons[PM_GRAY_DRAGON]))
mtmp->mhpmax = mtmp->mhp = mtmp->m_lev*8;
else if(!mtmp->m_lev) mtmp->mhpmax = mtmp->mhp = rnd(4);
else if(is_home_elemental(ptr))
mtmp->mhpmax = mtmp->mhp = 3 * d((int)mtmp->m_lev, 8);
else mtmp->mhpmax = mtmp->mhp = d((int)mtmp->m_lev, 8);
if (is_female(ptr)) mtmp->female = TRUE;
else if (is_male(ptr)) mtmp->female = FALSE;
else mtmp->female = rn2(2); /* ignored for neuters */
place_monster(mtmp, x, y);
mtmp->mcansee = mtmp->mcanmove = TRUE;
mtmp->mpeaceful = peace_minded(ptr);
switch(ptr->mlet) {
case S_MIMIC:
set_mimic_sym(mtmp);
break;
case S_SPIDER:
case S_SNAKE:
if(in_mklev)
if(x && y)
(void) mkobj_at(0, x, y, TRUE);
if(hides_under(ptr) && OBJ_AT(x, y))
mtmp->mundetected = TRUE;
break;
case S_STALKER:
case S_EEL:
mtmp->minvis = TRUE;
break;
case S_LEPRECHAUN:
mtmp->msleep = TRUE;
break;
case S_JABBERWOCK:
case S_NYMPH:
if(rn2(5) && !u.uhave.amulet) mtmp->msleep = TRUE;
break;
case S_ORC:
if(pl_character[0] == 'E') mtmp->mpeaceful = FALSE;
break;
case S_UNICORN:
if (sgn(u.ualign.type) == sgn(ptr->maligntyp))
mtmp->mpeaceful = TRUE;
break;
}
if (ptr == &mons[PM_CHAMELEON]) {
/* If you're protected with a ring, don't create
* any shape-changing chameleons -dgk
*/
if (Protection_from_shape_changers)
mtmp->cham = FALSE;
else {
mtmp->cham = TRUE;
(void) newcham(mtmp, rndmonst());
}
} else if (ptr == &mons[PM_WIZARD_OF_YENDOR]) {
mtmp->iswiz = TRUE;
flags.no_of_wizards++;
} else if (ptr == &mons[PM_VLAD_THE_IMPALER])
(void) mongets(mtmp, CANDELABRUM_OF_INVOCATION);
#ifdef MULDGN
else if (ptr->msound == MS_NEMESIS)
(void) mongets(mtmp, BELL_OF_OPENING);
#else
else if (ptr == &mons[PM_MEDUSA])
(void) mongets(mtmp, BELL_OF_OPENING);
#endif
if(in_mklev) {
if(((is_ndemon(ptr)) ||
(ptr == &mons[PM_WUMPUS]) ||
(ptr == &mons[PM_LONG_WORM]) ||
(ptr == &mons[PM_GIANT_EEL])) && !u.uhave.amulet && rn2(5))
mtmp->msleep = TRUE;
} else {
if(byyou) {
newsym(mtmp->mx,mtmp->my);
set_apparxy(mtmp);
}
}
if(is_dprince(ptr)) {
mtmp->mpeaceful = mtmp->minvis = TRUE;
if (uwep && uwep->oartifact == ART_EXCALIBUR)
mtmp->mpeaceful = mtmp->mtame = FALSE;
}
if ( (ptr == &mons[PM_LONG_WORM]) && (mtmp->wormno = get_wormno()) ) {
/* we can now create worms with tails - 11/91 */
initworm(mtmp, rn2(5));
if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, x, y);
}
set_malign(mtmp); /* having finished peaceful changes */
if(anything) {
if((ptr->geno & G_SGROUP) && rn2(2))
m_initsgrp(mtmp, mtmp->mx, mtmp->my);
else if(ptr->geno & G_LGROUP) {
if(rn2(3)) m_initlgrp(mtmp, mtmp->mx, mtmp->my);
else m_initsgrp(mtmp, mtmp->mx, mtmp->my);
}
}
if(is_armed(ptr))
m_initweap(mtmp); /* equip with weapons / armor */
m_initinv(mtmp); /* add on a few special items incl. more armor */
#ifdef MUSE
m_dowear(mtmp, TRUE);
#endif
if (!in_mklev)
newsym(mtmp->mx,mtmp->my); /* make sure the mon shows up */
return(mtmp);
}
boolean
enexto(cc, xx, yy, mdat)
coord *cc;
register xchar xx, yy;
struct permonst *mdat;
{
register xchar x,y;
coord foo[15], *tfoo;
int range, i;
int xmin, xmax, ymin, ymax;
tfoo = foo;
range = 1;
do { /* full kludge action. */
xmin = max(1, xx-range);
xmax = min(COLNO-1, xx+range);
ymin = max(0, yy-range);
ymax = min(ROWNO-1, yy+range);
for(x = xmin; x <= xmax; x++)
if(goodpos(x, ymin, (struct monst *)0, mdat)) {
tfoo->x = x;
#ifdef MAC_MPW32
( tfoo ) -> y = ymin ;
tfoo ++ ;
#else
(tfoo++)->y = ymin;
#endif
if(tfoo == &foo[15]) goto foofull;
}
for(x = xmin; x <= xmax; x++)
if(goodpos(x, ymax, (struct monst *)0, mdat)) {
tfoo->x = x;
#ifdef MAC_MPW32
( tfoo ) -> y = ymax ;
tfoo ++ ;
#else
(tfoo++)->y = ymax;
#endif
if(tfoo == &foo[15]) goto foofull;
}
for(y = ymin+1; y < ymax; y++)
if(goodpos(xmin, y, (struct monst *)0, mdat)) {
tfoo->x = xmin;
#ifdef MAC_MPW32
( tfoo ) -> y = y ;
tfoo ++ ;
#else
(tfoo++)->y = y;
#endif
if(tfoo == &foo[15]) goto foofull;
}
for(y = ymin+1; y < ymax; y++)
if(goodpos(xmax, y, (struct monst *)0, mdat)) {
tfoo->x = xmax;
#ifdef MAC_MPW32
( tfoo ) -> y = y ;
tfoo ++ ;
#else
(tfoo++)->y = y;
#endif
if(tfoo == &foo[15]) goto foofull;
}
range++;
if(range > ROWNO && range > COLNO) return FALSE;
} while(tfoo == foo);
foofull:
i = rn2((int)(tfoo - foo));
cc->x = foo[i].x;
cc->y = foo[i].y;
return TRUE;
}
int
goodpos(x, y, mtmp, mdat)
int x,y;
struct monst *mtmp; /* existing monster being moved, if any */
struct permonst *mdat;
{
struct monst *mtmp2;
if (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 || MON_AT(x, y))
return 0;
/* in many cases, we're trying to create a new monster, which
* can't go on top of the player or any existing monster.
* however, occasionally we are relocating engravings or objects,
* which could be colocated and thus get restricted a bit too much.
* oh well.
*/
if (x == u.ux && y == u.uy) return 0;
if ((mtmp2 = m_at(x, y)) && mtmp != mtmp2) return 0;
if (mdat) {
if (IS_POOL(levl[x][y].typ))
if (mdat == &playermon &&
(HLevitation || Wwalking || Magical_breathing))
return 1;
else return (is_flyer(mdat) || is_swimmer(mdat));
if (levl[x][y].typ == LAVAPOOL)
if (mdat == &playermon && (HLevitation))
return 1;
else return
(is_flyer(mdat) || (mdat == &mons[PM_FIRE_ELEMENTAL]));
if (passes_walls(mdat)) return 1;
}
if (!ACCESSIBLE(levl[x][y].typ)) return 0;
if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
return 0;
if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
return 0;
return 1;
}
#endif /* OVL1 */
#ifdef OVLB
/*
* rloc_to()
*
* Pulls a monster from its current position and places a monster at
* a new x and y. If oldx is 0, then the monster was not in the levels.monsters
* array. However, if oldx is 0, oldy may still have a value because mtmp is a
* migrating_mon. Worm tails are always placed randomly around the head of
* the worm.
*/
void
rloc_to(mtmp, x, y)
struct monst *mtmp;
register int x, y;
{
register int oldx = mtmp->mx, oldy = mtmp->my;
if(x == mtmp->mx && y == mtmp->my) /* that was easy */
return;
if (oldx) { /* "pick up" monster */
if(mtmp->wormno)
remove_worm(mtmp);
else {
remove_monster(oldx, oldy);
newsym(oldx, oldy); /* update old location */
}
}
place_monster(mtmp, x, y); /* put monster down */
if(mtmp->wormno) /* now put down tail */
place_worm_tail_randomly(mtmp, x, y);
if(u.ustuck == mtmp){
if(u.uswallow) {
u.ux = x;
u.uy = y;
docrt();
} else u.ustuck = 0;
}
newsym(x, y); /* update new location */
set_apparxy(mtmp); /* orient monster */
}
#endif /* OVLB */
#ifdef OVL2
void
rloc(mtmp)
struct monst *mtmp;
{
register int x = xupstair, y = yupstair, trycount;
/* if the wiz teleports away to heal, try the up staircase,
to block the player's escaping before he's healed */
if (!mtmp->iswiz || !goodpos(x, y, mtmp, mtmp->data)) {
trycount = 0;
do {
x = rn1(COLNO-3,2);
y = rn2(ROWNO);
} while(!goodpos(x,y,mtmp,mtmp->data) && ++trycount < 1000);
/* last ditch attempt to find a good place */
if (trycount >= 1000) {
for (x = 2; x < COLNO - 1; x++)
for (y = 0; y < ROWNO; y++)
if (goodpos(x,y,mtmp,mtmp->data))
goto found_atlast;
/* level either full of monsters or somehow faulty */
impossible("rloc(): couldn't relocate monster");
return;
}
}
found_atlast:;
rloc_to(mtmp, x, y);
}
void
rloc_shk(mtmp) /* to be used when teleporting a shopkeeper */
struct monst *mtmp;
{
register int x, y, ox, oy, trycount;
if(!mtmp->isshk) return;
trycount = 0;
do {
x = rn1(COLNO-3,2);
y = rn2(ROWNO);
} while(!goodpos(x,y,mtmp,mtmp->data) && ++trycount < 1000);
/* last ditch attempt to find a good place */
if (trycount >= 1000) {
for (x = 2; x < COLNO - 1; x++)
for (y = 0; y < ROWNO; y++)
if (goodpos(x,y,mtmp,mtmp->data))
goto found_ok;
/* this really shouldn't happen - after all, shopkeeper's
original position should always be available */
impossible("rloc_shk(): couldn't relocate shopkeeper");
return;
}
found_ok:;
ox = mtmp->mx;
oy = mtmp->my;
rloc_to(mtmp, x, y);
make_angry_shk(mtmp, ox, oy);
}
#endif /* OVL2 */
#ifdef OVLB
void
vloc(mtmp)
struct monst *mtmp;
{
register struct mkroom *croom = search_special(VAULT);
coord c;
if(croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, mtmp->data)) {
rloc_to(mtmp, c.x, c.y);
return;
}
rloc(mtmp);
}
#endif /* OVLB */
#ifdef OVL0
static boolean
cmavail() /* return TRUE if "common" monsters can be generated */
{
struct permonst *ptr;
for(ptr = &mons[0]; ptr != &mons[NUMMONS]; ptr++)
if(!uncommon(ptr)) return TRUE;
return FALSE;
}
/*
* shift the probability of a monster's generation by
* comparing the dungeon alignment and monster alignment.
* return an integer in the range of 0-5.
*/
static int
align_shift(ptr)
register struct permonst *ptr;
{
static long NEARDATA oldmoves = 0L; /* != 1, starting value of moves */
static s_level NEARDATA *lev;
register int alshift;
if(oldmoves != moves) {
lev = Is_special(&u.uz);
oldmoves = moves;
}
switch((lev) ? lev->flags.align : dungeons[u.uz.dnum].flags.align) {
default: /* just in case */
case AM_NONE: alshift = 0;
break;
case AM_LAWFUL: alshift = (ptr->maligntyp+20)/(2*ALIGNWEIGHT);
break;
case AM_NEUTRAL: alshift = (20 - abs(ptr->maligntyp))/ALIGNWEIGHT;
break;
case AM_CHAOTIC: alshift = (-(ptr->maligntyp-20))/(2*ALIGNWEIGHT);
break;
}
return alshift;
}
struct permonst *
rndmonst() /* select a random monster */
{
register struct permonst *ptr;
register int i, ct;
register int zlevel;
static int NEARDATA minmlev, NEARDATA maxmlev, NEARDATA accept;
static long NEARDATA oldmoves = 0L; /* != 1, starting value of moves */
#ifdef REINCARNATION
static boolean NEARDATA upper;
#endif
static boolean NEARDATA elemlevel;
#ifdef MULDGN
if(u.uz.dnum == quest_dnum && (ptr = qt_montype())) return(ptr);
#endif
if(oldmoves != moves) { /* must recalculate accept */
oldmoves = moves;
zlevel = level_difficulty();
if(!cmavail()) {
#ifdef DEBUG
pline("cmavail() fails!");
#endif
return((struct permonst *) 0);
}
/* determine the level of the weakest monster to make. */
minmlev = zlevel/6;
/* determine the level of the strongest monster to make. */
maxmlev = (zlevel + u.ulevel)>>1;
#ifdef REINCARNATION
upper = Is_rogue_level(&u.uz);
#endif
elemlevel = In_endgame(&u.uz) && !Is_astralevel(&u.uz);
/*
* Find out how many monsters exist in the range we have selected.
*/
accept = 0;
for(ct = 0, ptr = &mons[0] ; ptr != &mons[NUMMONS]; ct++, ptr++) {
if(tooweak(ct, minmlev) || toostrong(ct, maxmlev))
continue;
#ifdef REINCARNATION
if(upper && !isupper(def_monsyms[ptr->mlet])) continue;
#endif
if(elemlevel && wrong_elem_type(ptr)) continue;
if(uncommon(ptr)) continue;
accept += (ptr->geno & G_FREQ);
accept += align_shift(ptr);
}
}
if(!accept) {
#ifdef DEBUG
pline("no accept!");
#endif
return((struct permonst *) 0);
}
/*
* Now, select a monster at random.
*/
ct = rnd(accept);
for(i = 0,ptr = &mons[0]; ptr != &mons[NUMMONS] && ct > 0; i++,ptr++) {
if(tooweak(i, minmlev) || toostrong(i, maxmlev))
continue;
#ifdef REINCARNATION
if(upper & !isupper(def_monsyms[ptr->mlet])) continue;
#endif
if(elemlevel && wrong_elem_type(ptr)) continue;
if(uncommon(ptr)) continue;
ct -= (ptr->geno & G_FREQ);
ct -= align_shift(ptr);
}
if(ct > 0) {
#ifdef DEBUG
pline("no count!");
#endif
return((struct permonst *) 0);
}
return(--ptr); /* subtract extra increment */
}
#endif /* OVL0 */
#ifdef OVL1
/* The routine below is used to make one of the multiple types
* of a given monster class. The second parameter specifies a
* special casing bit mask to allow any of the normal genesis
* masks to be deactivated. Returns 0 if no monsters
* in that class can be made.
*/
struct permonst *
mkclass(class,spc)
char class;
int spc;
{
register int first, last, num = 0;
int maxmlev, mask = (G_GENOD | G_EXTINCT | G_NOGEN | G_UNIQ) & ~spc;
maxmlev = level_difficulty() >> 1;
if(class < 1 || class >= MAXMCLASSES) {
impossible("mkclass called with bad class!");
return((struct permonst *) 0);
}
/* Assumption #1: monsters of a given class are contiguous in the
* mons[] array.
*/
for(first = 0; first < NUMMONS; first++)
if (mons[first].mlet == class) break;
if (first == NUMMONS) return((struct permonst *) 0);
for(last = first; last < NUMMONS && mons[last].mlet == class; last++)
if(!(mons[last].geno & mask)) {
/* consider it */
if(num && toostrong(last, maxmlev) && rn2(2)) break;
num += mons[last].geno & G_FREQ;
}
if(!num) return((struct permonst *) 0);
/* Assumption #2: monsters of a given class are presented in ascending
* order of strength.
*/
for(num = rnd(num); num > 0; first++)
if(!(mons[first].geno & mask)) {
/* skew towards lower value monsters at lower exp. levels */
if(adj_lev(&mons[first]) > (u.ulevel*2)) num--;
num -= mons[first].geno & G_FREQ;
}
first--; /* correct an off-by-one error */
return(&mons[first]);
}
int
adj_lev(ptr) /* adjust strength of monsters based on u.uz and u.ulevel */
register struct permonst *ptr;
{
int tmp, tmp2;
if((tmp = ptr->mlevel) > 49) return(50); /* "special" demons/devils */
tmp2 = (level_difficulty() - tmp);
if(tmp2 < 0) tmp--; /* if mlevel > u.uz decrement tmp */
else tmp += (tmp2 / 5); /* else increment 1 per five diff */
tmp2 = (u.ulevel - ptr->mlevel); /* adjust vs. the player */
if(tmp2 > 0) tmp += (tmp2 / 4); /* level as well */
tmp2 = (3 * ((int) ptr->mlevel))/ 2; /* crude upper limit */
return((tmp > tmp2) ? tmp2 : (tmp > 0 ? tmp : 0)); /* 0 lower limit */
}
#endif /* OVL1 */
#ifdef OVLB
struct permonst *
grow_up(mtmp,victim) /* mon mtmp "grows up" to a bigger version. */
register struct monst *mtmp;
register struct monst *victim;
{
register int newtype;
register struct permonst *ptr = mtmp->data;
if (ptr->mlevel >= 50 || is_golem(ptr) || is_home_elemental(ptr)
|| is_mplayer(ptr))
/* doesn't grow up, has strange hp calculation so might be
* weakened by tests below */
return ptr;
if (victim) {
mtmp->mhpmax = mtmp->mhpmax + (1 + rn2((int)victim->m_lev+1));
if (mtmp->mhpmax <= (8 * (int)mtmp->m_lev)
|| (mtmp->m_lev == 0 && mtmp->mhpmax <= 4))
/* not ready to grow up */
return ptr;
}
#ifdef MUSE
/* else it's a gain level potion; always go up a level */
else {
int foo=rnd(8);
mtmp->mhp += foo;
mtmp->mhpmax += foo;
}
#endif
newtype = little_to_big(monsndx(ptr));
if ((int) (++mtmp->m_lev) >= mons[newtype].mlevel
&& newtype != monsndx(ptr)) {
if (mons[newtype].geno & G_GENOD) { /* allow G_EXTINCT */
pline("As %s grows up into %s, %s dies!",
mon_nam(mtmp),
an(mons[newtype].mname),
mon_nam(mtmp));
mondied(mtmp);
return (struct permonst *)0;
}
mtmp->data = &mons[newtype];
mtmp->m_lev = mons[newtype].mlevel;
}
if (newtype == monsndx(ptr) && victim &&
(int) mtmp->m_lev > (3*(int)mtmp->data->mlevel) / 2)
mtmp->m_lev = (3*(int)mtmp->data->mlevel) / 2;
if (mtmp->m_lev > 0) {
if (mtmp->mhp > (int) mtmp->m_lev * 8)
mtmp->mhp = mtmp->m_lev * 8;
if (mtmp->mhpmax > (int) mtmp->m_lev * 8)
mtmp->mhpmax = mtmp->m_lev * 8;
}
return(mtmp->data);
}
#endif /* OVLB */
#ifdef OVL1
int
mongets(mtmp, otyp)
register struct monst *mtmp;
register int otyp;
{
register struct obj *otmp;
#ifdef MUSE
if (!otyp) return 0;
#endif
if((otmp = (otyp) ? mksobj(otyp,TRUE,FALSE) : mkobj((char)otyp,FALSE))) {
if (mtmp->data->mlet == S_DEMON) {
/* demons always get cursed objects */
curse(otmp);
} else if(is_lminion(mtmp->data)) {
/* lawful minions don't get cursed, bad, or rusting objects */
otmp->cursed = FALSE;
if(otmp->spe < 0) otmp->spe = 0;
otmp->oerodeproof = TRUE;
} else if(is_mplayer(mtmp->data) && is_sword(otmp))
otmp->spe = (3 + rn2(4));
if(otmp->otyp == CANDELABRUM_OF_INVOCATION) {
otmp->spe = 0;
otmp->age = 0L;
otmp->lamplit = FALSE;
otmp->blessed = otmp->cursed = FALSE;
}
mpickobj(mtmp, otmp);
return(otmp->spe);
} else return(0);
}
#endif /* OVL1 */
#ifdef OVLB
int
golemhp(type)
int type;
{
switch(type) {
case PM_STRAW_GOLEM: return 20;
case PM_ROPE_GOLEM: return 30;
case PM_LEATHER_GOLEM: return 40;
case PM_WOOD_GOLEM: return 50;
case PM_FLESH_GOLEM: return 40;
case PM_CLAY_GOLEM: return 50;
case PM_STONE_GOLEM: return 60;
case PM_IRON_GOLEM: return 80;
default: return 0;
}
}
#endif /* OVLB */
#ifdef OVL1
/*
* Alignment vs. yours determines monster's attitude to you.
* ( some "animal" types are co-aligned, but also hungry )
*/
boolean
peace_minded(ptr)
register struct permonst *ptr;
{
aligntyp mal = ptr->maligntyp, ual = u.ualign.type;
if (always_peaceful(ptr)) return TRUE;
if (always_hostile(ptr)) return FALSE;
#ifdef MULDGN
if (ptr->msound == MS_LEADER || ptr->msound == MS_GUARDIAN)
return TRUE;
if (ptr->msound == MS_NEMESIS) return FALSE;
#endif
/* the monster is hostile if its alignment is different from the
* player's */
if (sgn(mal) != sgn(ual)) return FALSE;
/* Negative monster hostile to player with Amulet. */
if (mal < A_NEUTRAL && u.uhave.amulet) return FALSE;
/* minions are hostile to players that have strayed at all */
if (is_minion(ptr)) return(u.ualign.record >= 0);
/* Last case: a chance of a co-aligned monster being
* hostile. This chance is greater if the player has strayed
* (u.ualign.record negative) or the monster is not strongly aligned.
*/
return !!rn2(16 + (u.ualign.record < -15 ? -15 : u.ualign.record)) &&
!!rn2(2 + abs(mal));
}
/* Set malign to have the proper effect on player alignment if monster is
* killed. Negative numbers mean it's bad to kill this monster; positive
* numbers mean it's good. Since there are more hostile monsters than
* peaceful monsters, the penalty for killing a peaceful monster should be
* greater than the bonus for killing a hostile monster to maintain balance.
* Rules:
* it's bad to kill peaceful monsters, potentially worse to kill always-
* peaceful monsters
* it's never bad to kill a hostile monster, although it may not be good
*/
void
set_malign(mtmp)
struct monst *mtmp;
{
schar mal = mtmp->data->maligntyp;
boolean coaligned;
if (mtmp->ispriest || mtmp->isminion) {
/* some monsters have individual alignments; check them */
if (mtmp->ispriest)
mal = EPRI(mtmp)->shralign;
else if (mtmp->isminion)
mal = EMIN(mtmp)->min_align;
/* unless alignment is none, set mal to -5,0,5 */
/* (see align.h for valid aligntyp values) */
if(mal != A_NONE)
mal *= 5;
}
coaligned = (sgn(mal) == sgn(u.ualign.type));
#ifdef MULDGN
if (mtmp->data->msound == MS_LEADER) {
mtmp->malign = -20;
} else
#endif
if (mal == A_NONE) {
if (mtmp->mpeaceful)
mtmp->malign = 0;
else
mtmp->malign = 20; /* really hostile */
} else if (always_peaceful(mtmp->data)) {
if (mtmp->mpeaceful)
mtmp->malign = -3*max(5,abs(mal));
else
mtmp->malign = 3*max(5,abs(mal)); /* renegade */
} else if (always_hostile(mtmp->data)) {
if (coaligned)
mtmp->malign = 0;
else
mtmp->malign = max(5,abs(mal));
} else if (coaligned) {
if (mtmp->mpeaceful)
mtmp->malign = -3*max(3,abs(mal));
else /* renegade */
mtmp->malign = max(3,abs(mal));
} else /* not coaligned and therefore hostile */
mtmp->malign = abs(mal);
}
#endif /* OVL1 */
#ifdef OVLB
static char NEARDATA syms[] = {
MAXOCLASSES, MAXOCLASSES+1, RING_CLASS, WAND_CLASS, WEAPON_CLASS,
FOOD_CLASS, GOLD_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS,
AMULET_CLASS, TOOL_CLASS, ROCK_CLASS, GEM_CLASS, SPBOOK_CLASS,
S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF,
};
void
set_mimic_sym(mtmp) /* KAA, modified by ERS */
register struct monst *mtmp;
{
int typ, roomno, rt;
unsigned appear, ap_type;
int s_sym;
struct obj *otmp;
int mx, my;
if (!mtmp) return;
mx = mtmp->mx; my = mtmp->my;
typ = levl[mx][my].typ;
/* only valid for INSIDE of room */
roomno = levl[mx][my].roomno - ROOMOFFSET;
if (roomno >= 0)
rt = rooms[roomno].rtype;
#ifdef SPECIALIZATION
else if (IS_ROOM(typ))
rt = OROOM, roomno = 0;
#endif
else rt = 0; /* roomno < 0 case for GCC_WARN */
if (OBJ_AT(mx, my)) {
ap_type = M_AP_OBJECT;
appear = level.objects[mx][my]->otyp;
} else if (IS_DOOR(typ) || IS_WALL(typ) ||
typ == SDOOR || typ == SCORR) {
ap_type = M_AP_FURNITURE;
/*
* If there is a wall to the left that connects to this
* location, then the mimic mimics a horizontal closed door.
* This does not allow doors to be in corners of rooms.
*/
if (mx != 0 &&
(levl[mx-1][my].typ == HWALL ||
levl[mx-1][my].typ == TLCORNER ||
levl[mx-1][my].typ == TRWALL ||
levl[mx-1][my].typ == BLCORNER ||
levl[mx-1][my].typ == TDWALL ||
levl[mx-1][my].typ == CROSSWALL||
levl[mx-1][my].typ == TUWALL ))
appear = S_hcdoor;
else
appear = S_vcdoor;
if(!mtmp->minvis || See_invisible)
block_point(mx,my); /* vision */
} else if (level.flags.is_maze_lev && rn2(2)) {
ap_type = M_AP_OBJECT;
appear = STATUE;
} else if (roomno < 0) {
ap_type = M_AP_OBJECT;
appear = BOULDER;
if(!mtmp->minvis || See_invisible)
block_point(mx,my); /* vision */
} else if (rt == ZOO || rt == VAULT) {
ap_type = M_AP_OBJECT;
appear = GOLD_PIECE;
} else if (rt == DELPHI) {
if (rn2(2)) {
ap_type = M_AP_OBJECT;
appear = STATUE;
} else {
ap_type = M_AP_FURNITURE;
appear = S_fountain;
}
} else if (rt == TEMPLE) {
ap_type = M_AP_FURNITURE;
appear = S_altar;
/*
* We won't bother with beehives, morgues, barracks, throne rooms
* since they shouldn't contain too many mimics anyway...
*/
} else if (rt >= SHOPBASE) {
s_sym = get_shop_item(rt - SHOPBASE);
if (s_sym < 0) {
ap_type = M_AP_OBJECT;
appear = -s_sym;
} else {
if (s_sym == RANDOM_CLASS)
s_sym = syms[rn2((int)sizeof(syms)-2) + 2];
goto assign_sym;
}
} else {
s_sym = syms[rn2((int)sizeof(syms))];
assign_sym:
if (s_sym >= MAXOCLASSES) {
ap_type = M_AP_FURNITURE;
appear = s_sym == MAXOCLASSES ? S_upstair : S_dnstair;
} else if (s_sym == GOLD_CLASS) {
ap_type = M_AP_OBJECT;
appear = GOLD_PIECE;
} else {
ap_type = M_AP_OBJECT;
if (s_sym == S_MIMIC_DEF) {
appear = STRANGE_OBJECT;
} else {
otmp = mkobj( (char) s_sym, FALSE );
appear = otmp->otyp;
/* make sure container contents are free'ed */
obfree(otmp, (struct obj *) 0);
}
}
}
mtmp->m_ap_type = ap_type;
mtmp->mappearance = appear;
}
#endif /* OVLB */
/*makemon.c*/